home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 January / macpower199701.bin / AMUG / Programming_10 / WASTE 1.3a1.sit / WASTE 1.3a1 Distribution / Demo / WEDemoMenus.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-23  |  24.4 KB  |  1,186 lines  |  [TEXT/CWIE]

  1. /*
  2.     WASTE Demo Project:
  3.     Menu Handling
  4.  
  5.     Copyright ゥ 1993-1996 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11. #ifndef __ALIASES__
  12. #include <Aliases.h>
  13. #endif
  14.  
  15. #ifndef __DEVICES__
  16. #include <Devices.h>
  17. #endif
  18.  
  19. #ifndef __LOWMEM__
  20. #include <LowMem.h>
  21. #endif
  22.  
  23. #ifndef __STANDARDFILE__
  24. #include <StandardFile.h>
  25. #endif
  26.  
  27. #ifndef __FILETYPESANDCREATORS__
  28. #include <FileTypesAndCreators.h>
  29. #endif
  30.  
  31. #ifndef __TOOLUTILS__
  32. #include <ToolUtils.h>
  33. #endif
  34.  
  35. #ifndef __WEDEMOAPP__
  36. #include "WEDemoIntf.h"
  37. #endif
  38.  
  39. #include "WETabs.h"
  40.  
  41. // resource types
  42.  
  43. #define kTypeMenuColorTable        'mctb'
  44.  
  45. // static variables
  46.  
  47. static Handle sColors ;        // handle to the 'mctb' resource for the Color menu
  48.  
  49. // constants used by DoClose()
  50.  
  51. enum {
  52.     kButtonSave            = 1,
  53.     kButtonCancel,
  54.     kButtonDontSave
  55. };
  56.  
  57. void SetDefaultDirectory ( const FSSpec * spec )
  58. {
  59.     LMSetCurDirStore ( spec -> parID ) ;
  60.     LMSetSFSaveDisk ( - spec -> vRefNum ) ;
  61. }
  62.  
  63. static pascal Boolean MySFDialogFilter( DialogRef dialog, EventRecord *event, SInt16 *item, void *yourData )
  64. {
  65. #pragma unused ( item, yourData )
  66.  
  67.     //     intercept window events directed to windows behind the dialog
  68.     if ( ( event->what == updateEvt ) || ( event->what == activateEvt ) )
  69.     {
  70.         if ( (WindowRef) event->message != GetDialogWindow( dialog ) )
  71.         {
  72.             DoWindowEvent( event );
  73.         }
  74.     }
  75.  
  76.     return false;
  77. }
  78.  
  79. static ModalFilterYDUPP GetMySFDialogFilter( void )
  80. {
  81. #ifdef __cplusplus
  82.     static ModalFilterYDUPP sFilterUPP = NewModalFilterYDProc( MySFDialogFilter );
  83. #else
  84.     static ModalFilterYDUPP sFilterUPP = nil;
  85.     if ( sFilterUPP == nil )
  86.     {
  87.         sFilterUPP = NewModalFilterYDProc( MySFDialogFilter );
  88.     }
  89. #endif
  90.  
  91.     return sFilterUPP;
  92. }
  93.  
  94. SInt16    FindMenuItemText( MenuRef menu, ConstStr255Param stringToFind )
  95. {
  96.     SInt16        item;
  97.     Str255        itemString;
  98.  
  99.     for ( item = CountMenuItems( menu ); item >= 1; item-- )
  100.     {
  101.         GetMenuItemText( menu, item, itemString );
  102.         if ( EqualString( itemString, stringToFind, false, false ) )
  103.             break;
  104.     }
  105.  
  106.     return item;
  107. }
  108.  
  109. Boolean    EqualColor( const RGBColor *rgb1, const RGBColor *rgb2 )
  110. {
  111.     return ( (rgb1->red == rgb2->red) && (rgb1->green == rgb2->green) && (rgb1->blue == rgb2->blue) );
  112. }
  113.  
  114.  
  115. void PrepareMenus ( void )
  116. {
  117.     WindowRef        window;
  118.     WEReference        we;
  119.     MenuRef            menu;
  120.     MenuCRsrcPtr    pColors;
  121.     SInt16            item;
  122.     Str255            itemText;
  123.     SInt32            selStart, selEnd;
  124.     SInt32            threshold;
  125.     WEActionKind    actionKind;
  126.     WEStyleMode        mode;
  127.     TextStyle        ts;
  128.     Boolean            temp;
  129.  
  130.     // get a pointer to the frontmost window, if any
  131.  
  132.     window = FrontWindow ( ) ;
  133.  
  134.     // get associated WE instance
  135.  
  136.     we = ( window != nil ) ? GetWindowWE ( window ) : nil ;
  137.  
  138.     // *** FILE MENU ***
  139.  
  140.     menu = GetMenuHandle ( kMenuFile ) ;
  141.  
  142.     // first disable all items
  143.  
  144.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  145.     {
  146.         DisableItem ( menu, item ) ;
  147.     }
  148.  
  149.     // New, Open, and Quit are always enabled
  150.  
  151.     EnableItem ( menu, kItemNew ) ;
  152.     EnableItem ( menu, kItemOpen ) ;
  153.     EnableItem ( menu, kItemQuit ) ;
  154.  
  155.     // enable Close and Save As if there is an active window
  156.  
  157.     if ( window != nil )
  158.     {
  159.         EnableItem ( menu, kItemClose ) ;
  160.         EnableItem ( menu, kItemSaveAs ) ;
  161.  
  162.         // enable Save is the active window is dirty
  163.  
  164.         if ( WEGetModCount ( we ) > 0 )
  165.         {
  166.             EnableItem ( menu, kItemSave ) ;
  167.         }
  168.     }
  169.  
  170.     // *** EDIT MENU ***
  171.  
  172.     menu = GetMenuHandle ( kMenuEdit ) ;
  173.  
  174.     // first, disable all items
  175.  
  176.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  177.     {
  178.         DisableItem ( menu, item ) ;
  179.     }
  180.  
  181.     // by default, the Undo menu item should read "Can't Undo"
  182.  
  183.     GetIndString ( itemText, kUndoStringsID, 1 ) ;
  184.     SetMenuItemText ( menu, kItemUndo, itemText ) ;
  185.  
  186.     if ( window != nil )
  187.     {
  188.         // enable Paste if there's anything pasteable on the Clipboard
  189.  
  190.         if ( WECanPaste ( we ) )
  191.         {
  192.             EnableItem ( menu, kItemPaste ) ;
  193.         }
  194.  
  195.         // enable Undo if anything can be undone
  196.  
  197.         actionKind = WEGetUndoInfo ( & temp, we ) ;
  198.  
  199.         if ( actionKind != weAKNone )
  200.         {
  201.             EnableItem ( menu, kItemUndo ) ;
  202.  
  203.             // change the Undo menu item to "Undo/Redo" + name of action to undo/redo
  204.  
  205.             GetIndString ( itemText, kUndoStringsID, 2 * actionKind + temp ) ;
  206.             SetMenuItemText ( menu, kItemUndo, itemText ) ;
  207.         }
  208.  
  209.         // enable Select All if there is anything to select
  210.  
  211.         if ( WEGetTextLength ( we ) > 0 )
  212.         {
  213.             EnableItem ( menu, kItemSelectAll ) ;
  214.         }
  215.  
  216.         // get the current selection range
  217.  
  218.         WEGetSelection ( & selStart, & selEnd, we ) ;
  219.         if ( selStart != selEnd )
  220.         {
  221.             // enable Cut, Copy, and Clear if the selection range is not empty
  222.  
  223.             EnableItem ( menu, kItemCut ) ;
  224.             EnableItem ( menu, kItemCopy ) ;
  225.             EnableItem ( menu, kItemClear ) ;
  226.         }
  227.  
  228.         // determine which style attributes are continuous over the current selection range
  229.         // we'll need this information in order to check the Font/Size/Style/Color menus properly
  230.  
  231.         mode = weDoAll ;    // query about all attributes
  232.         WEContinuousStyle ( & mode, & ts, we ) ;
  233.     }
  234.     else
  235.     {
  236.         mode = 0 ;          // no window, so check no items
  237.     }
  238.  
  239.     // *** FONT MENU ***
  240.  
  241.     menu = GetMenuHandle ( kMenuFont ) ;
  242.  
  243.     // first, remove all check marks
  244.  
  245.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  246.     {
  247.         CheckItem ( menu, item, false ) ;
  248.     }
  249.  
  250.     // if there is a continuous font all over the selection range, check the
  251.     // corresponding menu item
  252.  
  253.     if ( mode & weDoFont )
  254.     {
  255.         GetFontName ( ts . tsFont, itemText ) ;
  256.         CheckItem ( menu, FindMenuItemText ( menu, itemText ), true ) ;
  257.     }
  258.  
  259.     // *** SIZE MENU ***
  260.  
  261.     menu = GetMenuHandle( kMenuSize );
  262.  
  263.     // first, remove all check marks
  264.  
  265.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  266.     {
  267.         CheckItem ( menu, item, false ) ;
  268.     }
  269.  
  270.     // if there is a continuous font size all over the selection range
  271.     // check the corresponding menu item
  272.  
  273.     if ( mode & weDoSize )
  274.     {
  275.         NumToString ( ts . tsSize, itemText ) ;
  276.         CheckItem ( menu, FindMenuItemText ( menu, itemText ), true ) ;
  277.     }
  278.  
  279.     // *** STYLE MENU ***
  280.  
  281.     menu = GetMenuHandle ( kMenuStyle ) ;
  282.  
  283.     // first, remove all check marks
  284.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  285.     {
  286.         CheckItem ( menu, item, false ) ;
  287.     }
  288.  
  289.     // check the style menu items corresponding to style attributes
  290.     if ( mode & weDoFace )
  291.     {
  292.         if ( ts.tsFace == normal )
  293.         {
  294.             CheckItem( menu, kItemPlainText, true );
  295.         }
  296.  
  297.         for ( item = kItemBold; item <= kItemExtended; item ++ )
  298.         {
  299.             if (ts.tsFace & ( 1 << ( item - kItemBold ) ) )
  300.             {
  301.                 CheckItem( menu, item, true );
  302.             }
  303.         }
  304.     }
  305.  
  306.     // *** COLOR MENU ***
  307.  
  308.     menu = GetMenuHandle ( kMenuColor ) ;
  309.  
  310.     // first, remove all check marks
  311.  
  312.     for ( item = CountMenuItems ( menu ) ; item >= 1; item -- )
  313.     {
  314.         CheckItem ( menu, item, false ) ;
  315.     }
  316.  
  317.     // if there is a continuous color all over the selection range,
  318.     // check the corresponding menu item (if any )
  319.  
  320.     if ( mode & weDoColor )
  321.     {
  322.         pColors = * ( MenuCRsrcHandle ) sColors ;
  323.         for ( item = pColors -> numEntries - 1 ; item >= 0 ; item -- )
  324.         {
  325.             if ( EqualColor ( & ts.tsColor, & pColors -> mcEntryRecs [ item ] . mctRGB2 ) )
  326.             {
  327.                 CheckItem ( menu, pColors -> mcEntryRecs [ item ] . mctItem, true ) ;
  328.             }
  329.  
  330.         } // end for loop
  331.     }
  332.  
  333.     // *** FEATURES MENU ***
  334.  
  335.     menu = GetMenuHandle( kMenuFeatures );
  336.  
  337.     // first remove all check marks
  338.     // (except the first two items, which have submenus!)
  339.  
  340.     for ( item = CountMenuItems ( menu ) ; item >= 3 ; item -- )
  341.     {
  342.         CheckItem ( menu, item, false ) ;
  343.     }
  344.  
  345.     if ( window != nil )
  346.     {
  347.         // mark each item according to the corresponding feature
  348.  
  349.         if ( WEIsTabHooks ( we ) )
  350.         {
  351.             CheckItem ( menu, kItemTabHooks, true ) ;
  352.             DisableItem ( menu, kItemAlignment ) ;
  353.             DisableItem ( menu, kItemDirection ) ;
  354.         }
  355.         else
  356.         {
  357.             EnableItem ( menu, kItemAlignment ) ;
  358.             EnableItem ( menu, kItemDirection ) ;
  359.         }
  360.  
  361.         if ( WEFeatureFlag ( weFAutoScroll, weBitTest, we ) )
  362.         {
  363.             CheckItem ( menu, kItemAutoScroll, true ) ;
  364.         }
  365.  
  366.          if ( WEFeatureFlag ( weFOutlineHilite, weBitTest, we ) )
  367.          {
  368.             CheckItem ( menu, kItemOutlineHilite, true ) ;
  369.         }
  370.  
  371.         if ( WEFeatureFlag( weFReadOnly, weBitTest, we ))
  372.         {
  373.             CheckItem ( menu, kItemReadOnly, true ) ;
  374.         }
  375.  
  376.         if ( WEFeatureFlag ( weFIntCutAndPaste, weBitTest, we ) )
  377.         {
  378.             CheckItem ( menu, kItemIntCutAndPaste, true ) ;
  379.         }
  380.  
  381.         if ( WEFeatureFlag( weFDragAndDrop, weBitTest, we ))
  382.         {
  383.             CheckItem ( menu, kItemDragAndDrop, true ) ;
  384.         }
  385.  
  386.         if ( ( WEGetInfo ( weTranslucencyThreshold, & threshold, we ) == noErr ) && ( threshold > 0 ) )
  387.         {
  388.             CheckItem ( menu, kItemTranslucentDrags, true ) ;
  389.         }
  390.  
  391.         if ( WEFeatureFlag( weFDrawOffscreen, weBitTest, we ) )
  392.         {
  393.             CheckItem ( menu, kItemOffscreenDrawing, true ) ;
  394.         }
  395.     }
  396.  
  397.     // *** ALIGNMENT MENU ***
  398.  
  399.     menu = GetMenuHandle ( kMenuAlignment ) ;
  400.  
  401.     // first, remove all check marks
  402.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  403.     {
  404.         CheckItem ( menu, item, false ) ;
  405.     }
  406.  
  407.     if ( window != nil )
  408.     {
  409.         // find the Aligment menu item corresponding to the current alignment
  410.         switch ( WEGetAlignment ( we ) )
  411.         {
  412.             case weFlushLeft:
  413.                 item = kItemAlignLeft ;
  414.                 break ;
  415.  
  416.             case weFlushRight:
  417.                 item = kItemAlignRight ;
  418.                 break ;
  419.  
  420.             case weFlushDefault:
  421.                 item = kItemAlignDefault ;
  422.                 break ;
  423.  
  424.             case weCenter:
  425.                 item = kItemCenter ;
  426.                 break ;
  427.  
  428.             case weJustify:
  429.                 item = kItemJustify ;
  430.                 break ;
  431.         }
  432.  
  433.         // check the menu item
  434.         CheckItem ( menu, item, true ) ;
  435.     }
  436.  
  437.     // *** DIRECTION MENU ***
  438.  
  439.     menu = GetMenuHandle ( kMenuDirection ) ;
  440.  
  441.     // first, remove all check marks
  442.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  443.     {
  444.         CheckItem ( menu, item, false ) ;
  445.     }
  446.  
  447.     if ( window != nil )
  448.     {
  449.         // find the Direction menu item corresponding to the current direction
  450.         switch ( WEGetDirection ( we ) )
  451.         {
  452.             case weDirDefault:
  453.                 item = kItemDirectionDefault ;
  454.                 break ;
  455.  
  456.             case weDirLeftToRight:
  457.                 item = kItemDirectionLR ;
  458.                 break ;
  459.  
  460.             case weDirRightToLeft:
  461.                 item = kItemDirectionRL ;
  462.                 break ;
  463.         }
  464.  
  465.         // check the menu item
  466.         CheckItem ( menu, item, true ) ;
  467.     }
  468. }
  469.  
  470. void DoDeskAcc ( SInt16 menuItem )
  471. {
  472.     Str255 deskAccessoryName ;
  473.  
  474.     GetMenuItemText ( GetMenuHandle ( kMenuApple ), menuItem, deskAccessoryName ) ;
  475.     OpenDeskAcc ( deskAccessoryName ) ;
  476. }
  477.  
  478. OSErr DoNew( void )
  479. {
  480.     // create a new window from scratch
  481.     return CreateWindow( nil );
  482. }
  483.  
  484. OSErr DoOpen( void )
  485. {
  486.     StandardFileReply        reply;
  487.     SFTypeList                typeList;
  488.     OSErr                    err = noErr;
  489.     Point                    where = { -1, -1 };  // auto center dialog
  490.  
  491.     // set up a list of file types we can open for StandardGetFile
  492.     typeList[0] = kTypeText;
  493.     typeList[1] = ftSimpleTextDocument;
  494.  
  495.     // put up the standard open dialog box.
  496.     // (we use CustomGetFile instead of StandardGetFile because we want to provide
  497.     // our own dialog filter procedure that takes care of updating our windows)
  498.     CustomGetFile( nil, 2, typeList, &reply, 0, where, nil, GetMySFDialogFilter( ), nil, nil, nil );
  499.  
  500.     // if the user ok'ed the dialog, create a new window from the specified file
  501.     if ( reply.sfGood )
  502.         err = CreateWindow( &reply.sfFile );
  503.     else
  504.         err = userCanceledErr;
  505.  
  506.     return err;
  507. }
  508.  
  509. OSErr SaveWindow( const FSSpec *pFileSpec, WindowRef window )
  510. {
  511.     DocumentHandle    hDocument;
  512.     AliasHandle        alias = nil;
  513.     OSErr            err;
  514.  
  515.     hDocument = GetWindowDocument(window);
  516.     ForgetHandle( & (*hDocument)->fileAlias );
  517.  
  518.     // save the text
  519.  
  520.     if ( ( err = WriteTextFile( pFileSpec, (*hDocument)->we ) ) == noErr )
  521.     {
  522.         SetWTitle( window, pFileSpec->name );
  523.  
  524.         // replace the old window alias (if any) with a new one created from pFileSpec
  525.         NewAlias( nil, pFileSpec, &alias );
  526.  
  527.         // if err, alias will be nil, and it's not fatal, just will make subsequent saves annoying
  528.         (* hDocument)->fileAlias = (Handle) alias;
  529.     }
  530.  
  531.     return err;
  532. }
  533.  
  534.  
  535. OSErr    DoSaveAs( const FSSpec *suggestedTarget, WindowRef window )
  536. {
  537.     StringHandle        hPrompt;
  538.     Str255                defaultName;
  539.     StandardFileReply    reply;
  540.     Point                where = { -1, -1 }; // autocenter's dialog
  541.     OSErr                err;
  542.  
  543.     // get the prompt string for CustomPutFile from a string resource and lock it
  544.     hPrompt = GetString( kPromptStringID );
  545.     HLockHi( (Handle) hPrompt );
  546.  
  547.     // if a suggested target file is provided, use its name as the default name
  548.     if ( suggestedTarget != nil )
  549.     {
  550.         PStringCopy( suggestedTarget->name, defaultName );
  551.         SetDefaultDirectory( suggestedTarget );
  552.     }
  553.     else
  554.     {
  555.         // otherwise use the window title as default name for CustomPutFile
  556.         GetWTitle( window, defaultName );
  557.     }
  558.  
  559.     // put up the standard Save dialog box
  560.     CustomPutFile( *hPrompt, defaultName, &reply, 0, where, nil, GetMySFDialogFilter(), nil, nil, nil );
  561.  
  562.     // unlock the string resource
  563.     HUnlock( (Handle)hPrompt );
  564.  
  565.     // if the user ok'ed the dialog, save the window to the specified file
  566.     if ( reply.sfGood )
  567.         err = SaveWindow( &reply.sfFile, window );
  568.     else
  569.         err = userCanceledErr;
  570.  
  571.     return err;
  572. }
  573.  
  574. OSErr    DoSave( WindowRef window )
  575. {
  576.     FSSpec        spec;
  577.     FSSpecPtr    suggestedTarget = nil;
  578.     Boolean        promptForNewFile = true;
  579.     Boolean        aliasTargetWasChanged;
  580.     OSErr        err;
  581.  
  582.     // resolve the alias associated with this window, if any
  583.  
  584.     if ( (* GetWindowDocument(window) )->fileAlias != nil )
  585.     {
  586.         if ( ( ResolveAlias( nil, (AliasHandle) (* GetWindowDocument(window))->fileAlias, &spec, &aliasTargetWasChanged ) == noErr ) )
  587.         {
  588.             if ( aliasTargetWasChanged )
  589.                 suggestedTarget = &spec;
  590.             else
  591.                 promptForNewFile = false;
  592.         }
  593.     }
  594.  
  595.     // if no file has been previously associated with this window, or if the
  596.     // alias resolution has failed, or if the alias target was changed
  597.     // prompt the user for a new destination
  598.  
  599.     if ( promptForNewFile )
  600.         err = DoSaveAs( suggestedTarget, window );
  601.     else
  602.         err = SaveWindow( &spec, window );
  603.  
  604.     return err;
  605. }
  606.  
  607. static pascal Boolean SaveChangesDialogFilter( DialogRef dialog, EventRecord *event, SInt16 *item )
  608. {
  609.     //    map command + D to the "Don't Save" button
  610.     if ( ( event->what == keyDown ) && ( event->modifiers & cmdKey ) && ( ( event->message & charCodeMask ) == 'd' ) )
  611.     {
  612.         //    flash the button briefly
  613.         FlashButton( dialog, kButtonDontSave );
  614.  
  615.         //    fake an event in the button
  616.         *item = kButtonDontSave;
  617.         return true;
  618.     }
  619.  
  620.     //    route everything else to our default handler
  621.     return CallModalFilterProc( GetMyStandardDialogFilter( ), dialog, event, item );
  622. }
  623.  
  624. OSErr DoClose( ClosingOption closing, SavingOption saving, WindowRef window )
  625. {
  626.     Str255        s1, s2;
  627.     SInt16        alertResult;
  628.     OSErr        err;
  629. #ifdef __cplusplus
  630.     static ModalFilterUPP sFilterProc = NewModalFilterProc( SaveChangesDialogFilter );
  631. #else
  632.     static ModalFilterUPP sFilterProc = nil;
  633.     if ( sFilterProc == nil )
  634.     {
  635.         sFilterProc = NewModalFilterProc( SaveChangesDialogFilter );
  636.     }
  637. #endif
  638.  
  639.     // is this window dirty?
  640.     if ( WEGetModCount( GetWindowWE(window) ) > 0 )
  641.     {
  642.         // do we have to ask the user whether to save changes?
  643.  
  644.         if ( saving == savingAsk )
  645.         {
  646.             // prepare the parametric strings to be used in the Save Changes alert box
  647.  
  648.             GetWTitle( window, s1 );
  649.  
  650.             GetIndString( s2, kClosingQuittingStringsID, 1 + closing );
  651.             ParamText( s1, s2, nil, nil );
  652.  
  653.             // put up the Save Changes? alert box
  654.  
  655.             SetCursor( &qd.arrow );
  656.  
  657.             alertResult = Alert( kAlertSaveChanges, sFilterProc );
  658.  
  659.             // exit if the user canceled the alert box
  660.  
  661.             if ( alertResult == kButtonCancel )
  662.                 return userCanceledErr;
  663.  
  664.             if ( alertResult == kButtonSave )
  665.                 saving = savingYes;
  666.             else
  667.                 saving = savingNo;
  668.         }
  669.  
  670.         if ( saving == savingYes )
  671.         {
  672.             if ( ( err = DoSave( window ) ) != noErr )
  673.                 return err;
  674.         }
  675.     }
  676.  
  677.     // destroy the window
  678.     DestroyWindow( window );
  679.  
  680.     return noErr;
  681. }
  682.  
  683. OSErr DoQuit( SavingOption saving )
  684. {
  685.     WindowRef window;
  686.     OSErr err;
  687.  
  688.     // close all windows
  689.     do
  690.     {
  691.         if ( ( window = FrontWindow( ) ) != nil )
  692.         {
  693.             if ( ( err = DoClose( closingApplication, saving, window ) ) != noErr )
  694.                 return err;
  695.         }
  696.     } while ( window != nil );
  697.  
  698.     // set a flag so we drop out of the event loop
  699.     gExiting = true;
  700.  
  701.     return noErr;
  702. }
  703.  
  704. void DoAppleChoice( SInt16 menuItem )
  705. {
  706.     if ( menuItem == kItemAbout )
  707.         DoAboutBox( kDialogAboutBox );
  708.     else
  709.         DoDeskAcc( menuItem );
  710. }
  711.  
  712. void DoFileChoice( SInt16 menuItem )
  713. {
  714.     WindowRef window = FrontWindow();
  715.  
  716.     switch( menuItem )
  717.     {
  718.         case kItemNew:
  719.             DoNew( );
  720.             break;
  721.  
  722.         case kItemOpen:
  723.             DoOpen( );
  724.             break;
  725.  
  726.         case kItemClose:
  727.             DoClose( closingWindow, savingAsk, window );
  728.             break;
  729.  
  730.         case kItemSave:
  731.             DoSave( window );
  732.             break;
  733.  
  734.         case kItemSaveAs:
  735.             DoSaveAs( nil, window );
  736.             break;
  737.  
  738.         case kItemQuit:
  739.             DoQuit( savingAsk );
  740.             break;
  741.     }
  742. }
  743.  
  744. void DoEditChoice ( SInt16 menuItem )
  745. {
  746.     WindowRef window ;
  747.     WEReference we ;
  748.  
  749.     // do nothing is no window is active
  750.     if ( ( window = FrontWindow ( ) ) == nil )
  751.     {
  752.         return ;
  753.     }
  754.  
  755.     we = GetWindowWE ( window ) ;
  756.  
  757.     switch ( menuItem )
  758.     {
  759.         case kItemUndo:
  760.              WEUndo ( we ) ;
  761.             break ;
  762.  
  763.         case kItemCut :
  764.             WECut ( we ) ;
  765.             break ;
  766.  
  767.         case kItemCopy:
  768.             WECopy ( we ) ;
  769.             break ;
  770.  
  771.         case kItemPaste:
  772.             WEPaste ( we ) ;
  773.             break ;
  774.  
  775.         case kItemClear:
  776.             WEDelete ( we ) ;
  777.             break ;
  778.  
  779.         case kItemSelectAll:
  780.             WESetSelection ( 0, LONG_MAX, we ) ;
  781.             break ;
  782.     }
  783. }
  784.  
  785. void DoFontChoice ( SInt16 menuItem, EventModifiers modifiers )
  786. {
  787.     WindowRef        window;
  788.     Str255            fontName;
  789.     WEStyleMode        mode;
  790.     TextStyle        ts;
  791.  
  792.     //    do nothing if there is no front window
  793.     if ( ( window = FrontWindow ( ) ) == nil )
  794.     {
  795.         return ;
  796.     }
  797.  
  798.     GetMenuItemText ( GetMenuHandle ( kMenuFont ), menuItem, fontName ) ;
  799.     GetFNum ( fontName, & ts . tsFont ) ;
  800.  
  801.     //    use script-preserving mode by default (see WASTE docs)
  802.     //    force font change across the whole selection if the option key was held down
  803.     mode = ( modifiers & optionKey ) ? weDoFont : ( weDoFont + weDoPreserveScript + weDoExtractSubscript ) ;
  804.  
  805.     //    set the font of the selection
  806.     WESetStyle ( mode, & ts, GetWindowWE ( window ) ) ;
  807. }
  808.  
  809. void DoSizeChoice ( SInt16 menuItem )
  810. {
  811.     WindowRef        window;
  812.     Str255            sizeString;
  813.     SInt32            size;
  814.     WEStyleMode        mode;
  815.     TextStyle        ts;
  816.  
  817.     //    do nothing if there is no front window
  818.     if ( ( window = FrontWindow ( ) ) == nil )
  819.     {
  820.         return ;
  821.     }
  822.  
  823.     if ( menuItem <= kItemLastSize )
  824.     {
  825.         GetMenuItemText ( GetMenuHandle ( kMenuSize ), menuItem, sizeString ) ;
  826.         StringToNum ( sizeString, & size ) ;
  827.         ts . tsSize = size ;
  828.         mode = weDoSize ;
  829.     }
  830.     else if ( menuItem == kItemSmaller )
  831.     {
  832.         ts . tsSize = - 1 ;
  833.         mode = weDoAddSize ;
  834.     }
  835.     else if ( menuItem == kItemLarger )
  836.     {
  837.         ts . tsSize = + 1 ;
  838.         mode = weDoAddSize ;
  839.     }
  840. /*
  841.     else if ( menuItem == kItemOtherSize )
  842.     {
  843.         //    get current selection size (if continuous)
  844.         ts . tsSize = 12 ;
  845.         mode = weDoSize ;
  846.         WEContinuousStyle ( & mode, & ts, GetWindowWE ( window ) ) ;
  847.  
  848.         //    let the user choose any size via the Font Size picker
  849.         if ( DoSizeDialog ( & ts . tsSize ) != noErr )
  850.         {
  851.             return ;
  852.         }
  853.         mode = weDoSize ;
  854.     }
  855. */
  856.     else
  857.     {
  858.         return ;
  859.     }
  860.  
  861.     //    set the size of the selection
  862.     WESetStyle ( mode, & ts, GetWindowWE ( window ) ) ;
  863. }
  864.  
  865. void DoStyleChoice ( SInt16 menuItem )
  866. {
  867.     WindowRef         window ;
  868.     TextStyle         ts ;
  869.  
  870.     //    do nothing if there is no front window
  871.     if ( ( window = FrontWindow ( ) ) == nil )
  872.     {
  873.         return ;
  874.     }
  875.  
  876.     if ( menuItem == kItemPlainText )
  877.     {
  878.         ts . tsFace = normal ;
  879.     }
  880.     else
  881.     {
  882.         ts . tsFace = 1 << ( menuItem - kItemBold ) ;
  883.     }
  884.  
  885.     //    set the style of the selection
  886.     WESetStyle ( weDoFace + weDoToggleFace, & ts, GetWindowWE ( window ) ) ;
  887. }
  888.  
  889. void DoColorChoice ( SInt16 menuItem )
  890. {
  891.     WindowRef             window ;
  892.     MenuCRsrcPtr         pColors ;
  893.     SInt16                 i ;
  894.     TextStyle            ts ;
  895.  
  896.     // do nothing if there is no front window
  897.     if ( ( window = FrontWindow( ) ) == nil )
  898.     {
  899.         return ;
  900.     }
  901.  
  902.     if ( menuItem <= kItemLastColor )
  903.     {
  904.         // find the color corresponding to the chosen menu item
  905.         pColors = * ( MenuCRsrcHandle ) sColors ;
  906.         for ( i = pColors -> numEntries - 1 ; i >= 0 ; i -- )
  907.         {
  908.             if ( pColors -> mcEntryRecs [ i ] . mctItem == menuItem )
  909.             {
  910.                 ts . tsColor = pColors -> mcEntryRecs [ i ] . mctRGB2 ;
  911.                 break ;
  912.             }
  913.         }
  914.     }
  915. /*
  916.     else if ( menuItem == kItemOtherColor )
  917.     {
  918.         //    get current selection color (if continuous)
  919.         WEStyleMode mode = weDoColor ;
  920.  
  921.         ts . tsColor . red = 0 ;
  922.         ts . tsColor . green = 0 ;
  923.         ts . tsColor . blue = 0 ;
  924.         WEContinuousStyle ( & mode, & ts, GetWindowWE ( window ) ) ;
  925.  
  926.         //    let the user choose any color via the Color picker
  927.         if ( DoColorDialog ( & ts . tsColor ) != noErr )
  928.         {
  929.             return ;
  930.         }
  931.     }
  932. */
  933.     else
  934.     {
  935.         return ;
  936.     }
  937.  
  938.     //    set the color of the selection
  939.     WESetStyle ( weDoColor, & ts, GetWindowWE ( window ) ) ;
  940. }
  941.  
  942. void DoAlignmentChoice ( SInt16 menuItem )
  943. {
  944.     WindowRef window ;
  945.     WEAlignment alignment ;
  946.  
  947.     if ( ( window = FrontWindow( ) ) == nil )
  948.     {
  949.         return ;
  950.     }
  951.  
  952.     switch( menuItem )
  953.     {
  954.         case kItemAlignDefault:
  955.             alignment = weFlushDefault ;
  956.             break ;
  957.  
  958.         case kItemAlignLeft:
  959.             alignment = weFlushLeft ;
  960.             break ;
  961.  
  962.         case kItemCenter:
  963.             alignment = weCenter ;
  964.             break ;
  965.  
  966.         case kItemAlignRight:
  967.             alignment = weFlushRight ;
  968.             break ;
  969.  
  970.         case kItemJustify:
  971.             alignment = weJustify ;
  972.             break ;
  973.     }
  974.  
  975.     // set the alignment mode (this automatically redraws the text)
  976.     WESetAlignment ( alignment, GetWindowWE ( window ) ) ;
  977. }
  978.  
  979. void DoDirectionChoice ( SInt16 menuItem )
  980. {
  981.     WindowRef window;
  982.     WEDirection direction;
  983.  
  984.     if ( ( window = FrontWindow ( ) ) == nil )
  985.     {
  986.         return ;
  987.     }
  988.  
  989.     switch ( menuItem )
  990.     {
  991.         case kItemDirectionDefault:
  992.             direction = weDirDefault ;
  993.             break ;
  994.  
  995.         case kItemDirectionLR:
  996.             direction = weDirLeftToRight ;
  997.             break ;
  998.  
  999.         case kItemDirectionRL:
  1000.             direction = weDirRightToLeft ;
  1001.             break ;
  1002.     }
  1003.  
  1004.     // set the primary line direction (this automatically redraws the text)
  1005.     WESetDirection ( direction, GetWindowWE ( window ) ) ;
  1006. }
  1007.  
  1008. void DoFeatureChoice ( SInt16 menuItem )
  1009. {
  1010.     WindowRef window ;
  1011.     WEReference we ;
  1012.     SInt32 threshold ;
  1013.  
  1014.     if ( ( window = FrontWindow ( ) ) == nil )
  1015.         return ;
  1016.  
  1017.     we = GetWindowWE ( window ) ;
  1018.  
  1019.     if ( menuItem == kItemTabHooks )
  1020.     {
  1021.         // install or remove our custom tab hooks
  1022.  
  1023.         if ( ! WEIsTabHooks ( we ) )
  1024.         {
  1025.             // left-align the text (the hooks only work with left-aligned text )
  1026.             WESetAlignment ( weFlushLeft, we ) ;
  1027.  
  1028.             // force a LR primary direction
  1029.             // (the hooks don't work with bidirectional text anyway)
  1030.             WESetDirection ( weDirLeftToRight, we ) ;
  1031.  
  1032.             // install tab hooks
  1033.             WEInstallTabHooks ( we ) ;
  1034.         }
  1035.         else
  1036.         {
  1037.             // remove tab hooks
  1038.             WERemoveTabHooks ( we ) ;
  1039.         }
  1040.  
  1041.         // turn the cursor into a wristwatch
  1042.         SetCursor ( * GetCursor ( watchCursor ) ) ;
  1043.  
  1044.         // recalculate link breaks and redraw the text
  1045.         WECalText ( we ) ;
  1046.         WEUpdate ( nil, we ) ;
  1047.     }
  1048.     else
  1049.     {
  1050.         switch ( menuItem )
  1051.         {
  1052.             case kItemAutoScroll:
  1053.                 WEFeatureFlag ( weFAutoScroll, weBitToggle, we ) ;
  1054.                 break;
  1055.  
  1056.             case kItemOutlineHilite:
  1057.                 WEFeatureFlag ( weFOutlineHilite, weBitToggle, we ) ;
  1058.                 break;
  1059.  
  1060.             case kItemReadOnly:
  1061.                 WEFeatureFlag ( weFReadOnly, weBitToggle, we ) ;
  1062.                 break;
  1063.  
  1064.             case kItemIntCutAndPaste:
  1065.                 WEFeatureFlag ( weFIntCutAndPaste, weBitToggle, we ) ;
  1066.                 break;
  1067.  
  1068.             case kItemDragAndDrop:
  1069.                 WEFeatureFlag ( weFDragAndDrop, weBitToggle, we ) ;
  1070.                 break;
  1071.  
  1072.             case kItemTranslucentDrags:
  1073.                 if ( WEGetInfo ( weTranslucencyThreshold, & threshold, we ) == noErr )
  1074.                 {
  1075.                     threshold = kStandardTranslucencyThreshold - threshold ;
  1076.                     WESetInfo ( weTranslucencyThreshold, & threshold, we ) ;
  1077.                 }
  1078.                 break;
  1079.  
  1080.             case kItemOffscreenDrawing:
  1081.                 WEFeatureFlag ( weFDrawOffscreen, weBitToggle, we ) ;
  1082.                 break;
  1083.         }
  1084.     }
  1085. }
  1086.  
  1087. void DoMenuChoice ( SInt32 menuChoice, EventModifiers modifiers )
  1088. {
  1089.     SInt16 menuID, menuItem ;
  1090.  
  1091.     // extract menu ID and menu item from menuChoice
  1092.  
  1093.     menuID = HiWord ( menuChoice ) ;
  1094.     menuItem = LoWord ( menuChoice ) ;
  1095.  
  1096.     // dispatch on menuID
  1097.  
  1098.     switch ( menuID )
  1099.     {
  1100.         case kMenuApple:
  1101.             DoAppleChoice ( menuItem ) ;
  1102.             break ;
  1103.  
  1104.         case kMenuFile:
  1105.             DoFileChoice ( menuItem ) ;
  1106.             break ;
  1107.  
  1108.         case kMenuEdit:
  1109.             DoEditChoice ( menuItem ) ;
  1110.             break ;
  1111.  
  1112.         case kMenuFont:
  1113.             DoFontChoice ( menuItem, modifiers ) ;
  1114.             break ;
  1115.  
  1116.         case kMenuSize:
  1117.             DoSizeChoice ( menuItem ) ;
  1118.             break ;
  1119.  
  1120.         case kMenuStyle:
  1121.             DoStyleChoice ( menuItem ) ;
  1122.             break ;
  1123.  
  1124.         case kMenuColor:
  1125.             DoColorChoice ( menuItem ) ;
  1126.             break ;
  1127.  
  1128.         case kMenuFeatures:
  1129.             DoFeatureChoice ( menuItem ) ;
  1130.             break ;
  1131.  
  1132.         case kMenuAlignment:
  1133.             DoAlignmentChoice ( menuItem ) ;
  1134.             break ;
  1135.  
  1136.         case kMenuDirection:
  1137.             DoDirectionChoice ( menuItem ) ;
  1138.             break ;
  1139.     }
  1140.  
  1141.     HiliteMenu ( 0 ) ;
  1142. }
  1143.  
  1144. OSErr InitializeMenus ( void )
  1145. {
  1146.     OSErr err = noErr ;
  1147.  
  1148.     // build up the whole menu bar from the 'MBAR' resource
  1149.     SetMenuBar ( GetNewMBar ( kMenuBarID ) ) ;
  1150.  
  1151.     // add names to the apple and Font menus
  1152.     AppendResMenu ( GetMenuHandle ( kMenuApple ), kTypeDeskAccessory ) ;
  1153.     AppendResMenu ( GetMenuHandle ( kMenuFont ), kTypeFont ) ;
  1154.  
  1155.     // insert the alignment and direction submenus into the hierarchical
  1156.     // portion of the menu list
  1157.     InsertMenu ( GetMenu ( kMenuAlignment ), -1 ) ;
  1158.     InsertMenu ( GetMenu ( kMenuDirection ), -1 ) ;
  1159.  
  1160.     // disable the "Drag and Drop Editing" item in the Features menu once and for all
  1161.     // if the Drag Manager isn't available
  1162.     if ( ! gHasDragAndDrop )
  1163.     {
  1164.         DisableItem ( GetMenuHandle ( kMenuFeatures ), kItemDragAndDrop ) ;
  1165.     }
  1166.  
  1167.     // disable the "Other" item in the Color menu if Color QuickDraw isn't available
  1168.     if ( ! gHasColorQD )
  1169.     {
  1170.         DisableItem ( GetMenuHandle ( kMenuColor ), kItemOtherColor ) ;
  1171.     }
  1172.  
  1173.     // load the menu color table for the color menu
  1174.     sColors = GetResource ( kTypeMenuColorTable, kMenuColor ) ;
  1175.     if ( ( err = ResError ( ) ) != noErr )
  1176.     {
  1177.         return err ;
  1178.     }
  1179.     HNoPurge ( sColors ) ;
  1180.  
  1181.     // draw the menu bar
  1182.     DrawMenuBar ( ) ;
  1183.  
  1184.     return err ;
  1185. }
  1186.